/**
 * @file hoc.jsx.
 * @author liaoxuezhi@baidu.com
 */
/* eslint fecs-indent: [0, "space", 2, 2] */

import * as React from 'react';
import {
  Component,
  PropTypes
} from "react";
import {findDOMNode} from 'react-dom';
import * as assign from 'object-assign';
import * as cx from 'classnames';
import {render} from '../renderer';
import {Overlay} from 'react-bootstrap';
import SimplePopOver from '../../widgets/simple-popover/simple-popover';
import {getDialogContainer, closest, matches} from '../../util/helper';
import * as keycode from 'keycode';
import {findDOMNode} from 'react-dom';
// import * as $ from 'jquery';

import '../form/panel-form';
let flag = false;



export const Enhance = (options = {}) => ComposedComponent => class QuickEditable extends Component {
  constructor(props, context) {
    super(props, context);

    const form = this.buildQuickEditForm(props);
    this.state = {
      editing: false,
      form
    };

    this.openQuickEdit = this.openQuickEdit.bind(this);
    this.closeQuickEdit = this.closeQuickEdit.bind(this);
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.handlePopOverSubmit = this.handlePopOverSubmit.bind(this);
    this.getOffset = this.getOffset.bind(this);
    this.handleKeyUp = this.handleKeyUp.bind(this);
    this.handleWindowKeyDown = this.handleWindowKeyDown.bind(this);
    this.handleWindowKeyPress = this.handleWindowKeyPress.bind(this);
  }

  componentDidMount() {
    if (flag) {
      return;
    }

    flag = true;
    document.body.addEventListener('keypress', this.handleWindowKeyPress);
    document.body.addEventListener('keydown', this.handleWindowKeyDown);
  }

  componentWillReceiveProps(nextProps) {
    const props = this.props;

    if (props.value !== nextProps.value || props.quickEdit !== nextProps.quickEdit) {
      const form = this.buildQuickEditForm(nextProps);
      this.setState({
        form
      });
    }
  }

  componentWillUnmount() {
    if (!flag) {
      return;
    }

    document.body.removeEventListener('keypress', this.handleWindowKeyPress);
    document.body.removeEventListener('keydown', this.handleWindowKeyDown);
    flag = false;
  }

  buildQuickEditForm(props) {
    if (!props.quickEdit) {
      return null;
    }

    const {
      name,
      value,
      quickEdit
    } = props;

    if (quickEdit.mode === 'inline') {
      return {
        className: 'quick-edit-form',
        submitText: '',
        mode: quickEdit.controls ? '' : (quickEdit.formMode || 'inline'),
        controls: quickEdit.controls ? quickEdit.controls : [
          assign({
            name,
            value,
            type: 'text'
          }, quickEdit)
        ]
      }
    }

    return {
      title: null,
      className: 'quick-edit-form',
      controls: [
        assign({
          name,
          value,
          type: 'text'
        }, quickEdit)
      ],
      actions: [
        {
          type: 'button',
          label: '取消'
        },

        {
          type: 'submit',
          className: 'btn-primary',
          label: '确认'
        }
      ]
    };
  }

  openQuickEdit(e) {
    e && e.preventDefault();
    this.setState({
      editing: !this.state.editing
    });
  }

  closeQuickEdit() {
    this.setState({
      editing: false
    }, () => {
      let el = findDOMNode(this);
      closest(el, 'table').querySelectorAll('td.td-quick-editable:focus').length || el && el.focus();
      // $(el).closest('table').find('td.td-quick-editable:focus').length || el && el.focus();
    });
  }

  handleKeyUp(e) {
    const code = keycode(e);
    if (code === 'space' && !~['INPUT', 'TEXTAREA'].indexOf(e.target.tagName)) {
      e.preventDefault();
      e.stopPropagation();

      this.openQuickEdit();
    }
  }

  handleWindowKeyPress(e) {
    let el;

    try {
      el = findDOMNode(this);
    } catch (e) {
      // 有可能没有清除干净。
      this.componentWillUnmount();
    }

    if (!el) {return;}
    const table = el.closest('table');
    if (!table || !table.contains(e.target)) {
      return;
    }
    
    if (keycode(e) === 'space' && !~['INPUT', 'TEXTAREA'].indexOf(e.target.tagName)) {
      e.preventDefault();
      e.stopPropagation();
      return false;
    }
  }

  handleWindowKeyDown(e) {
    const code = keycode(e);

    if (~['INPUT', 'TEXTAREA'].indexOf(e.target.tagName) || !~['up', 'down', 'left', 'right'].indexOf(code)) {
      return;
    }
    
    e.preventDefault();
    let el = findDOMNode(this);
    if (!el) {return;}

    let table = closest(el, 'table');
    if (!table) {
      return;
    }

    let current = table.querySelector('.td-quick-editable:focus');

    if (!current) {
      let dom = table.querySelector('.td-quick-editable[tabindex]');
      dom && dom.focus();
    } else {
      let prevTr, nextTr, prevTd, nextTd;

      switch (code) {
        case 'up':
          prevTr = current.parentNode.previousSibling;

          if (prevTr) {
            let index = current.cellIndex;
            prevTr.children[index].focus();
          }
          break;
        case 'down':
          nextTr = current.parentNode.nextSibling;

          if (nextTr) {
            let index = current.cellIndex;
            nextTr.children[index].focus();
          }
          break;
        case 'left':
          prevTd = current.previousElementSibling;

          while (prevTd) {
            if (matches(prevTd, '.td-quick-editable[tabindex]')) {
              break;
            }
            prevTd = prevTd.previousElementSibling;
          }

          if (prevTd) {
            prevTd.focus();
          } else if (current.parentNode.previousSibling) {
            let tds = current.parentNode.previousSibling.querySelectorAll('.td-quick-editable[tabindex]');

            if (tds.length) {
              tds[tds.length - 1].focus();
            }
          }
          break;
        case 'right':
          nextTd = current.nextSibling;
          while (nextTd) {
            if (matches(nextTd, '.td-quick-editable[tabindex]')) {
              break;
            }

            nextTd = nextTd.nextSibling;
          }

          if (nextTd) {
            nextTd.focus();
          } else if (current.parentNode.nextSibling) {
            nextTd = current.parentNode.nextSibling.querySelector('.td-quick-editable[tabindex]');

            if (nextTd) {
              nextTd.focus();
            }
          }
          break;
      }

    // let $table = $(el).closest('table');
    // let $current = $table.find('.td-quick-editable:focus');
    //
    // if (!$current.length) {
    //   $table.find('.td-quick-editable[tabindex]:first').focus();
    // } else {
    //   let $prevTr, $nextTr, $prevTd, $nextTd;
    //
    //   switch (code) {
    //     case 'up':
    //       $prevTr = $current.parent().prev();
    //
    //       if ($prevTr.length) {
    //         let index = $current.index();
    //         $prevTr.children().eq(index).focus();
    //       }
    //       break;
    //     case 'down':
    //       $nextTr = $current.parent().next();
    //
    //       if ($nextTr.length) {
    //         let index = $current.index();
    //         $nextTr.children().eq(index).focus();
    //       }
    //       break;
    //     case 'left':
    //       $prevTd = $current.prevAll('.td-quick-editable[tabindex]:first');
    //       if ($prevTd.length) {
    //         $prevTd.focus();
    //       } else if (($prevTr = $current.parent().prev()) && $prevTr.length) {
    //         $prevTr.find('.td-quick-editable[tabindex]:last').focus();
    //       }
    //       break;
    //     case 'right':
    //       $nextTd = $current.nextAll('.td-quick-editable[tabindex]:first');
    //       if ($nextTd.length) {
    //         $nextTd.focus();
    //       } else if (($nextTr = $current.parent().next()) && $nextTr.length) {
    //         $nextTr.find('.td-quick-editable[tabindex]:first').focus();
    //       }
    //       break;
    //   }
    }
  }

  handlePopOverSubmit(values) {
    const {
      name,
      item,
      onFieldValueChange,
      onFieldValueSave,
      quickEdit
    } = this.props;

    this.closeQuickEdit();

    let value = values[name];

    if (Array.isArray(value)) {
      value = value.map(item => typeof item === 'object' ? item.value : item).join(',');
    } else if (value && typeof value === 'object') {
      value = value.value;
    }

    quickEdit.saveImmediately ? onFieldValueSave(name, value, item) : onFieldValueChange(name, value, item);
  }

  handleChange(values) {
    const {
      item,
      onFieldValueChange,
      onFieldValueSave,
      quickEdit
    } = this.props;

    quickEdit.saveImmediately ? onFieldValueSave(values, item) : onFieldValueChange(values, item);
  }

  handleSubmit(values) {
    const {
      item,
      onFieldValueSave
    } = this.props;

    onFieldValueSave(values, item);
  }

  getOffset(box, current) {
    const dom = findDOMNode(this).getBoundingClientRect();
    const windowWidth = window.innerWidth;
    let x = (box.width - dom.width) / 2;

    // 右边放不下,放左边.
    if (current.x + x + box.width > windowWidth) {
      x = (dom.width - box.width) / 2;
    }

    return {
      x: x - 1,
      y: -dom.height + 1
    }
  }

  render() {
    let {
      className,
      quickEdit,
      disableQuickEdit,
      name,
      value,
      $path,
      data,
      onRequestAction,
      prefix,
      elementsOnly
    } = this.props;

    let subProps = {};

    if (quickEdit && !disableQuickEdit) {
      if (quickEdit.mode === 'inline') {
        const props = {
          className: cx(quickEdit.className || 'td-quick-editable-inline', className)
        };
        const Wrapper = options.wrapper || 'td';

        return (
          <Wrapper {...props}>
            {render(`${$path}/quick-edit/basic-form`, this.state.form, {
              autoFocus: false,
              data: data,
              onChange: this.handleChange,
              onSubmit: this.handleSubmit,
              onRequestAction,
              elementsOnly
            })}
          </Wrapper>
        );
      }

      const editing = this.state.editing;
      quickEdit.mode !== 'inline' && quickEdit.focusable === false || (subProps.tabIndex = '0');
      subProps.onKeyUp = this.handleKeyUp;

      className = cx(className, 'td-quick-editable', editing ? 'td-quick-editing' : null);

      if (!prefix && !editing) {
        subProps.prefix = <i key="edit-btn" className="fa fa-edit text-muted" onClick={this.openQuickEdit} />;
      }

      if (editing) {
        const sharedProps = {
          key: "overlay",
          container: getDialogContainer(),
          show: true,
          placement: 'bottom',
          target: () => findDOMNode(this),
          rootClose: true,
          onHide: this.closeQuickEdit
        };

        subProps.affix = (
          <Overlay {...sharedProps}>
            <SimplePopOver className="quick-edit-popover" offset={this.getOffset}>
              {render(`${$path}/quick-edit/panel-form`, this.state.form, {
                data: {
                  [name]: value
                },
                formRef: form => this.form = form,
                onRequestAction: btn => btn.type === 'submit' ? this.form.submit() :  this.closeQuickEdit(),
                onSubmit: this.handlePopOverSubmit
              })}
            </SimplePopOver>
          </Overlay>
        );
      }
    }

    return (
      <ComposedComponent {...this.props} className={className} {...subProps} />
    )
  }
};

export default Enhance;